import random
import redis
from flask import Blueprint, jsonify, g, request, current_app
from flask_restful import Api, Resource, reqparse
from utils.send_sms import SendSMS
from utils.jwt_tool import JwtTool
from utils.redis_tool import RedisTool
from models.model import db, User

user_bp = Blueprint("user_bp", __name__, url_prefix="/user")


# 此钩子函数，负责解析token
@user_bp.before_request
def login_gz():
    req = reqparse.RequestParser()
    req.add_argument("token", default="", location="headers")

    args = req.parse_args()

    j = JwtTool()
    payload = j.ver_token(args["token"])

    # 正常来说，已经解析出来token了
    # 再增加一个检测当前token 是否被封禁了
    rds_tool = RedisTool()
    key = "disable_token_" + args["token"]
    count = rds_tool.rds.exists(key)  # 如果说count的值为真，则说明当前token被封禁
    if count:
        payload = None

    g.user = payload


# 负责强制登录
def require_login(func):
    def warpper(*args, **kwargs):
        if not g.user:
            # return jsonify({
            #     "code": 403,
            #     "msg": "此用户未登录"
            # })
            return jsonify({
                "code": 666,
                "msg": "此用户未登录"
            })

        return func(*args, **kwargs)

    return warpper


api = Api(user_bp)


# 发送短信的类试图
class SmsCode(Resource):
    def post(self):
        # 获取前台传过来的数据
        req = reqparse.RequestParser()
        req.add_argument("mobile", required=True, help="手机号必须输入")
        args = req.parse_args()

        # 生成验证码
        code = random.randint(100000, 999999)

        sms = SendSMS()
        send_rs = sms.send_sms(args["mobile"], (str(code), 5))
        if send_rs:
            return jsonify({
                "code": 200,
                "msg": "发送成功"
            })
        else:
            return jsonify({
                "code": 400,
                "msg": "发送失败"
            })


class UserView(Resource):
    def post(self):
        # 获取参数
        req = reqparse.RequestParser()
        req.add_argument("mobile", required=True)
        req.add_argument("code", required=True)

        args = req.parse_args()

        # 要验证一下手机号
        sms = SendSMS()
        ver_rs = sms.ver_code(args["mobile"], args["code"])
        # if not ver_rs:
        # return jsonify({
        #     "code": 400,
        #     "msg": "验证码错误"
        # })

        # 走到这里，说明验证码验证成功

        # 去数据库查询、判断手机号是否存在
        user_info = User.query.filter(User.mobile == args["mobile"]).first()

        # 不存在，说明是第一次登录，就需要注册
        if not user_info:
            # 注册就是往用户表增加一条数据
            user = User(mobile=args["mobile"], user_name=args["mobile"])
            db.session.add(user)
            db.session.commit()

        # 走到这一步，就说明用户一定存在了，直接登录就可以了
        user_info = User.query.filter(User.mobile == args["mobile"]).first()

        # 生成Token
        # 实例化JWT工具类
        token_obj = JwtTool()
        token = token_obj.create_token({
            "user_id": user_info.uid,
            "mobile": args["mobile"]
        }, 2 * 3600)  # 有效期 2小时

        long_token = token_obj.create_token({
            "user_id": user_info.uid,
            "mobile": args["mobile"]
        }, 30 * 24 * 3600)  # 有效期 一月

        return jsonify({
            "code": 200,
            "msg": "登录成功",
            "user": {
                "uid": user_info.uid,
                "mobile": args["mobile"]
            },
            # 返回两个token,token:具体业务需要携带并且验证的，long_token负责在token失效之后，去换取新的token
            "token": token,
            "long_token": long_token
        })

    # 获取用户个人信息
    @require_login
    def get(self):
        user_id = g.user["user_id"]  # 拿到当前登录用户的ID
        user_info = User.query.filter(User.uid == user_id).first()  # 当前用户的所有信息

        if not user_info:
            return jsonify({
                "code": 400,
                "msg": "用户不存在"
            })

        head_img = "aoteman.png"
        if user_info.img:
            head_img = user_info.img

        head_img = current_app.config["QINIU_HOST"] + head_img

        return jsonify({
            "code": 200,
            "msg": "用户信息获取成功",
            "user": {
                "mobile": user_info.mobile,
                "follow_count": user_info.following_count,  # 关注数
                "fans_count": user_info.fans_count,  # 粉丝数
                "head_img": head_img,
            }
        })


class Token(Resource):
    def get(self):
        req = reqparse.RequestParser()
        req.add_argument("token2", default="", location="headers")
        args = req.parse_args()

        j = JwtTool()
        payload = j.ver_token(args["token2"])
        if not payload:
            return jsonify({
                "code": 400,
                "msg": "token失效"
            })

        # 生成一个新的token,返回回去
        new_token = j.create_token(payload, exp=2 * 3600)

        return jsonify({
            "code": 200,
            "msg": "获取新token成功",
            "token": new_token
        })

    # 封禁当前用户的token
    @require_login
    def delete(self):
        # 1.获取到token
        req = reqparse.RequestParser()
        req.add_argument("token", location="headers")
        args = req.parse_args()

        # 2. 把token封禁掉
        rds_tool = RedisTool()
        key = "disable_token_" + args["token"]
        rds_tool.rds.set(key, "1", ex=2 * 3600)

        # 3. 返回
        return jsonify({
            "code": 200,
            "msg": "退出登录"
        })


# 上传头像
class HeadImg(Resource):
    @require_login
    def post(self):
        # 把文件传到本地
        img = request.files.get("img")
        img.save("./static/" + img.filename)

        from utils.qiniu_upload import QiniuTool
        # 从本地上传到七牛云
        qn = QiniuTool()
        file_path = qn.upload_file("./static/" + img.filename, img.filename)

        # 存到当前用户的数据库
        try:
            User.query.filter(User.uid == g.user["user_id"]).update({
                "img": file_path
            })
            db.session.commit()
            return jsonify({
                "code": 200,
                "msg": "头像上传成功"
            })
        except Exception as e:
            print("修改头像报错", e)
            return jsonify({
                "code": 400,
                "msg": "头像上传失败"
            })


api.add_resource(UserView, "/user")
api.add_resource(SmsCode, "/sms")
api.add_resource(Token, "/new_token")
api.add_resource(HeadImg, "/head_img")
